home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / gfx / misc / gnuplot-src.lha / gnuplot-3.7.1src / gnuplot-3.7.1.lha / gnuplot-3.7.1 / datafile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-19  |  37.9 KB  |  1,418 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: datafile.c,v 1.11.2.1 1999/08/19 14:41:09 lhecking Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - datafile.c */
  6.  
  7. /*[
  8.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted,
  12.  * provided that the above copyright notice appear in all copies and
  13.  * that both that copyright notice and this permission notice appear
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the complete modified source code.  Modifications are to
  18.  * be distributed as patches to the released version.  Permission to
  19.  * distribute binaries produced by compiling modified sources is granted,
  20.  * provided you
  21.  *   1. distribute the corresponding source modifications from the
  22.  *    released version in the form of a patch file along with the binaries,
  23.  *   2. add special version identification to distinguish your version
  24.  *    in addition to the base release version number,
  25.  *   3. provide your name and address as the primary contact for the
  26.  *    support of your modified version, and
  27.  *   4. retain our contact information in regard to use of the base
  28.  *    software.
  29.  * Permission to distribute the released version of the source code along
  30.  * with corresponding source modifications in the form of a patch file is
  31.  * granted with same provisions 2 through 4 for binary distributions.
  32.  *
  33.  * This software is provided "as is" without express or implied warranty
  34.  * to the extent permitted by applicable law.
  35. ]*/
  36.  
  37. /* AUTHOR : David Denholm */
  38.  
  39. /*
  40.  * this file provides the functions to handle data-file reading..
  41.  * takes care of all the pipe / stdin / index / using worries
  42.  */
  43.  
  44. /*{{{  notes */
  45. /* couldn't decide how to implement 'thru' only for 2d and 'index'
  46.  * for only 3d, so I did them for both - I can see a use for
  47.  * index in 2d, especially for fit.
  48.  *
  49.  * I keep thru for backwards compatibility, and extend it to allow
  50.  * more natural plot 'data' thru f(y) - I (personally) prefer
  51.  * my syntax, but then I'm biased...
  52.  *
  53.  * - because I needed it, I have added a range of indexes...
  54.  * (s)plot 'data' [index i[:j]]
  55.  *
  56.  * also every a:b:c:d:e:f  - plot every a'th point from c to e,
  57.  * in every b lines from d to f
  58.  * ie for (line=d; line<=f; line+=b)
  59.  *     for (point=c; point >=e; point+=a)
  60.  *
  61.  *
  62.  * I dont like mixing this with the time series hack... I am
  63.  * very into modular code, so I would prefer to not have to
  64.  * have _anything_ to do with time series... for example,
  65.  * we just look at columns in file, and that is independent
  66.  * of 2d/3d. I really dont want to have to pass a flag to
  67.  * this is plot or splot. 
  68.  *
  69.  * use a global array df_timecol[] - cleared by df_open, then
  70.  * columns needing time set by client.
  71.  *
  72.  * Now that df_2dbinary() and df_3dbinary() are here, I am seriously
  73.  * tempted to move get_data() and get_3ddata() in here too
  74.  *
  75.  * public variables declared in this file.
  76.  *    int df_no_use_specs - number of columns specified with 'using'
  77.  *    int df_line_number  - for error reporting
  78.  *    int df_datum        - increases with each data point
  79.  *    TBOOLEAN df_binary  - it's a binary file
  80.  *        [ might change this to return value from df_open() ]
  81.  *    int df_eof          - end of file
  82.  *    int df_timecol[]    - client controls which cols read as time
  83.  *
  84.  * functions 
  85.  *   int df_open(int max_using)
  86.  *      parses thru / index / using on command line
  87.  *      max_using is max no of 'using' columns allowed
  88.  *      returns number of 'using' cols specified, or -1 on error (?)
  89.  *
  90.  *   int df_readline(double vector[], int max)
  91.  *      reads a line, does all the 'index' and 'using' manipulation
  92.  *      deposits values into vector[]
  93.  *      returns
  94.  *          number of columns parsed  [0=not blank line, but no valid data],
  95.  *          DF_EOF for EOF
  96.  *          DF_UNDEFINED - undefined result during eval of extended using spec
  97.  *          DF_FIRST_BLANK for first consecutive blank line
  98.  *          DF_SECOND_BLANK for second consecutive blank line
  99.  *            will return FIRST before SECOND
  100.  *
  101.  * if a using spec was given, lines not fulfilling spec are ignored.
  102.  * we will always return exactly the number of items specified
  103.  *
  104.  * if no spec given, we return number of consecutive columns we parsed.
  105.  * 
  106.  * if we are processing indexes, seperated by 'n' blank lines,
  107.  * we will return n-1 blank lines before noticing the index change
  108.  *
  109.  *   void df_close()
  110.  *     closes a currently open file.
  111.  *
  112.  *    void f_dollars(x)
  113.  *    void f_column()    actions for expressions using $i, column(j), etc
  114.  *    void f_valid()     
  115.  * 
  116.  *
  117.  * line parsing slightly differently from previous versions of gnuplot...
  118.  * given a line containing fewer columns than asked for, gnuplot used to make
  119.  * up values... I say that if I have explicitly said 'using 1:2:3', then if
  120.  * column 3 doesn't exist, I dont want this point...
  121.  *
  122.  * a column number of 0 means generate a value... as before, this value
  123.  * is useful in 2d as an x value, and is reset at blank lines.
  124.  * a column number of -1 means the (data) line number (not the file line
  125.  * number).  splot 'file' using 1  is equivalent to
  126.  * splot 'file' using 0:-1:1
  127.  * column number -2 is the index. It was put in to kludge multi-branch
  128.  * fitting.
  129.  *
  130.  * 20/5/95 : accept 1.23d4 in place of e (but not in scanf string)
  131.  *         : autoextend data line buffer and MAX_COLS
  132.  *
  133.  * 11/8/96 : add 'columns' -1 for suggested y value, and -2 for
  134.  *           current index.
  135.  *           using 1:-1:-2  and  column(-1)  are supported.
  136.  *           $-1 and $-2 are not yet supported, because of the
  137.  *           way the parser works
  138.  *
  139.  */
  140. /*}}} */
  141.  
  142. #include "plot.h"
  143. #include "fnproto.h"        /* check prototypes against our defns */
  144. #include "binary.h"
  145. #include "setshow.h"
  146.  
  147. /* if you change this, change the scanf in readline */
  148. #define NCOL   7        /* max using specs     */
  149.  
  150. /*{{{  static fns */
  151. #if 0                /* not used */
  152. static int get_time_cols __PROTO((char *fmt));
  153. static void mod_def_usespec __PROTO((int specno, int jump));
  154. #endif
  155. static int check_missing __PROTO((char *s));
  156. static char *df_gets __PROTO((void));
  157. static int df_tokenise __PROTO((char *s));
  158. static float **df_read_matrix __PROTO((int *rows, int *columns));
  159. /*}}} */
  160.  
  161. /*{{{  variables */
  162. struct use_spec_s {
  163.     int column;
  164.     struct at_type *at;
  165. };
  166.  
  167. /* public variables client might access */
  168.  
  169. int df_no_use_specs;        /* how many using columns were specified */
  170. int df_line_number;
  171. int df_datum;            /* suggested x value if none given */
  172. TBOOLEAN df_matrix = FALSE;    /* is this a matrix splot */
  173. int df_eof = 0;
  174. int df_timecol[NCOL];
  175. TBOOLEAN df_binary = FALSE;    /* this is a binary file */
  176.  
  177. /* private variables */
  178.  
  179. /* in order to allow arbitrary data line length, we need to use the heap
  180.  * might consider free-ing it in df_close, especially for small systems
  181.  */
  182. static char *line = NULL;
  183. static int max_line_len = 0;
  184.  
  185. static FILE *data_fp = NULL;
  186. static TBOOLEAN pipe_open = FALSE;
  187. static TBOOLEAN mixed_data_fp = FALSE;
  188.  
  189. #ifndef MAXINT            /* should there be one already defined ? */
  190. # ifdef INT_MAX            /* in limits.h ? */
  191. #  define MAXINT INT_MAX
  192. # else
  193. #  define MAXINT ((~0)>>1)
  194. # endif
  195. #endif
  196.  
  197. /* stuff for implementing index */
  198. static int blank_count = 0;    /* how many blank lines recently */
  199. static int df_lower_index = 0;    /* first mesh required */
  200. static int df_upper_index = MAXINT;
  201. static int df_index_step = 1;    /* 'every' for indices */
  202. static int df_current_index;    /* current mesh */
  203.  
  204. /* stuff for every point:line */
  205. static int everypoint = 1;
  206. static int firstpoint = 0;
  207. static int lastpoint = MAXINT;
  208. static int everyline = 1;
  209. static int firstline = 0;
  210. static int lastline = MAXINT;
  211. static int point_count = -1;    /* point counter - preincrement and test 0 */
  212. static int line_count = 0;    /* line counter */
  213.  
  214. /* parsing stuff */
  215. static struct use_spec_s use_spec[NCOL];
  216. static char df_format[MAX_LINE_LEN + 1];
  217.  
  218. /* rather than three arrays which all grow dynamically, make one
  219.  * dynamic array of this structure
  220.  */
  221.  
  222. typedef struct df_column_struct {
  223.     double datum;
  224.     enum {
  225.     DF_MISSING, DF_BAD, DF_GOOD
  226.     } good;
  227.     char *position;
  228. } df_column_struct;
  229.  
  230. static df_column_struct *df_column = NULL;    /* we'll allocate space as needed */
  231. static int df_max_cols = 0;    /* space allocated */
  232. static int df_no_cols;        /* cols read */
  233. static int fast_columns;    /* corey@cac optimization */
  234.  
  235. /* external variables we need */
  236.  
  237. extern int c_token, num_tokens;
  238. extern char timefmt[];        /* I would rather not need this, but ... */
  239. /* columns needing timefmt are passed in df_timecol[] after df_open */
  240.  
  241. /* jev -- for passing data thru user-defined function */
  242. extern struct udft_entry ydata_func;
  243. extern struct udft_entry *dummy_func;
  244. extern char dummy_var[MAX_NUM_VAR][MAX_ID_LEN + 1];
  245. extern char c_dummy_var[MAX_NUM_VAR][MAX_ID_LEN + 1];
  246.  
  247. extern double min_array[], max_array[];
  248. /*}}} */
  249.  
  250.  
  251. /*{{{  static char *df_gets() */
  252. static char *df_gets()
  253. {
  254.     int len = 0;
  255.  
  256.     if (!fgets(line, max_line_len, data_fp))
  257.     return NULL;
  258.  
  259.     if (mixed_data_fp)
  260.     ++inline_num;
  261.  
  262.     for (;;) {
  263.     len += strlen(line + len);
  264.  
  265.     if (len > 0 && line[len - 1] == '\n') {
  266.         /* we have read an entire text-file line.
  267.          * Strip the trailing linefeed and return
  268.          */
  269.         line[len - 1] = 0;
  270.         return line;
  271.     }
  272.     /* buffer we provided may not be full - dont grab extra
  273.      * memory un-necessarily. This may trap a problem with last
  274.      * line in file not being properly terminated - each time
  275.      * through a replot loop, it was doubling buffer size
  276.      */
  277.  
  278.     if ((max_line_len - len) < 32)
  279.         line = gp_realloc(line, max_line_len *= 2, "datafile line buffer");
  280.  
  281.     if (!fgets(line + len, max_line_len - len, data_fp))
  282.         return line;    /* unexpected end of file, but we have something to do */
  283.     }
  284.  
  285.     /* NOTREACHED */
  286.     return NULL;
  287. }
  288. /*}}} */
  289.  
  290. /*{{{  static int df_tokenise(s) */
  291. static int df_tokenise(s)
  292. char *s;
  293. {
  294.     /* implement our own sscanf that takes 'missing' into account,
  295.      * and can understand fortran quad format
  296.      */
  297.  
  298.     df_no_cols = 0;
  299.  
  300.     while (*s) {
  301.  
  302.     /* check store - double max cols or add 20, whichever is greater */
  303.     if (df_max_cols <= df_no_cols)
  304.         df_column = (df_column_struct *) gp_realloc(df_column, (df_max_cols += (df_max_cols < 20 ? 20 : df_max_cols)) * sizeof(df_column_struct), "datafile column");
  305.  
  306.     /* have always skipped spaces at this point */
  307.     df_column[df_no_cols].position = s;
  308.  
  309.     if (check_missing(s))
  310.         df_column[df_no_cols].good = DF_MISSING;
  311.     else {
  312. #ifdef OSK
  313.         /* apparently %n does not work. This implementation
  314.          * is just as good as the non-OSK one, but close
  315.          * to a release (at last) we make it os-9 specific
  316.          */
  317.         int count;
  318.         char *p = strpbrk(s, "dqDQ");
  319.         if (p != NULL)
  320.         *p = 'e';
  321.  
  322.         count = sscanf(s, "%lf", &df_column[df_no_cols].datum);
  323. #else
  324.         /* cannot trust strtod - eg strtod("-",&p) */
  325.         int used;
  326.         int count;
  327.         int dfncp1 = df_no_cols + 1;
  328.  
  329. /*
  330.  * optimizations by Corey Satten, corey@cac.washington.edu
  331.  */
  332.         if (fast_columns == 0 ||
  333.         df_no_use_specs > 0 && (use_spec[0].column == dfncp1 ||
  334.           df_no_use_specs > 1 && (use_spec[1].column == dfncp1 ||
  335.           df_no_use_specs > 2 && (use_spec[2].column == dfncp1 ||
  336.           df_no_use_specs > 3 && (use_spec[3].column == dfncp1 ||
  337.           df_no_use_specs > 4 && (use_spec[4].column == dfncp1 ||
  338.                       df_no_use_specs > 5))))) ||
  339.         df_no_use_specs == 0) {
  340.  
  341. #ifndef NO_FORTRAN_NUMS
  342.         count = sscanf(s, "%lf%n", &df_column[df_no_cols].datum, &used);
  343. #else
  344.         while (isspace(*s))
  345.             ++s;
  346.         count = *s ? 1 : 0;
  347.         df_column[df_no_cols].datum = atof(s);
  348. #endif /* NO_FORTRAN_NUMS */
  349.         } else {
  350.         /* skip any space at start of column */
  351.         /* HBB tells me that the cast must be to
  352.          * unsigned char instead of int. */
  353.         while (isspace((unsigned char) *s))
  354.             ++s;
  355.         count = *s ? 1 : 0;
  356.         /* skip chars to end of column */
  357.         used = 0;
  358.         while (!isspace((unsigned char) *s) && (*s != NUL))
  359.             ++s;
  360.         }
  361.  
  362.         /* it might be a fortran double or quad precision.
  363.          * 'used' is only safe if count is 1
  364.          */
  365.  
  366. #ifndef NO_FORTRAN_NUMS
  367.         if (count == 1 &&
  368.         (s[used] == 'd' || s[used] == 'D' ||
  369.          s[used] == 'q' || s[used] == 'Q')) {
  370.         /* might be fortran double */
  371.         s[used] = 'e';
  372.         /* and try again */
  373.         count = sscanf(s, "%lf", &df_column[df_no_cols].datum);
  374.         }
  375. #endif /* NO_FORTRAN_NUMS */
  376. #endif /* OSK */
  377.         df_column[df_no_cols].good = count == 1 ? DF_GOOD : DF_BAD;
  378.     }
  379.  
  380.     ++df_no_cols;
  381.     /*{{{  skip chars to end of column */
  382.     while ((!isspace((int)*s)) && (*s != '\0'))
  383.         ++s;
  384.     /*}}} */
  385.     /*{{{  skip spaces to start of next column */
  386.     while (isspace((int)*s))
  387.         ++s;
  388.     /*}}} */
  389.     }
  390.  
  391.     return df_no_cols;
  392. }
  393. /*}}} */
  394.  
  395. /*{{{  static float **df_read_matrix() */
  396. /* reads a matrix from a text file
  397.  * stores in same storage format as fread_matrix
  398.  */
  399.  
  400. static float **df_read_matrix(rows, cols)
  401. int *rows, *cols;
  402. {
  403.     int max_rows = 0;
  404.     int c;
  405.     float **rmatrix = NULL;
  406.  
  407.     char *s;
  408.  
  409.     *rows = 0;
  410.     *cols = 0;
  411.  
  412.     for (;;) {
  413.     if (!(s = df_gets())) {
  414.         df_eof = 1;
  415.         return rmatrix;    /* NULL if we have not read anything yet */
  416.     }
  417.     while (isspace((int)*s))
  418.         ++s;
  419.  
  420.     if (!*s || is_comment(*s)) {
  421.         if (rmatrix)
  422.         return rmatrix;
  423.         else
  424.         continue;
  425.     }
  426.     if (mixed_data_fp && is_EOF(*s)) {
  427.         df_eof = 1;
  428.         return rmatrix;
  429.     }
  430.     c = df_tokenise(s);
  431.  
  432.     if (!c)
  433.         return rmatrix;
  434.  
  435.     if (*cols && c != *cols) {
  436.         /* its not regular */
  437.         int_error("Matrix does not represent a grid", NO_CARET);
  438.     }
  439.     *cols = c;
  440.  
  441.     if (*rows >= max_rows) {
  442.         rmatrix = gp_realloc(rmatrix, (max_rows += 10) * sizeof(float *), "df_matrix");
  443.     }
  444.     /* allocate a row and store data */
  445.     {
  446.         int i;
  447.         float *row = rmatrix[*rows] = (float *) gp_alloc(c * sizeof(float), "df_matrix row");
  448.  
  449.         for (i = 0; i < c; ++i) {
  450.         if (df_column[i].good != DF_GOOD)
  451.             int_error("Bad number in matrix", NO_CARET);
  452.  
  453.         row[i] = (float) df_column[i].datum;
  454.         }
  455.  
  456.         ++*rows;
  457.     }
  458.     }
  459. }
  460.  
  461. /*}}} */
  462.  
  463.  
  464. /*{{{  int df_open(max_using) */
  465. int df_open(max_using)
  466. int max_using;
  467.  
  468. /* open file, parsing using/thru/index stuff
  469.  * return number of using specs  [well, we have to return something !]
  470.  */
  471.  
  472. {
  473.     /* now allocated dynamically */
  474.     static char *filename = NULL;
  475.     int i;
  476.     int name_token;
  477.  
  478.     fast_columns = 1;        /* corey@cac */
  479.  
  480.     /*{{{  close file if necessary */
  481.     if (data_fp)
  482.     df_close();
  483.     /*}}} */
  484.  
  485.     /*{{{  initialise static variables */
  486.     df_format[0] = NUL;    /* no format string */
  487.  
  488.     df_no_use_specs = 0;
  489.  
  490.     for (i = 0; i < NCOL; ++i) {
  491.     use_spec[i].column = i + 1;    /* default column */
  492.     use_spec[i].at = NULL;    /* no expression */
  493.     }
  494.  
  495.     if (max_using > NCOL)
  496.     max_using = NCOL;
  497.  
  498.     df_datum = -1;        /* it will be preincremented before use */
  499.     df_line_number = 0;        /* ditto */
  500.  
  501.     df_lower_index = 0;
  502.     df_index_step = 1;
  503.     df_upper_index = MAXINT;
  504.  
  505.     df_current_index = 0;
  506.     blank_count = 2;
  507.     /* by initialising blank_count, leading blanks will be ignored */
  508.  
  509.     everypoint = everyline = 1;    /* unless there is an every spec */
  510.     firstpoint = firstline = 0;
  511.     lastpoint = lastline = MAXINT;
  512.  
  513.     df_eof = 0;
  514.  
  515.     memset(df_timecol, 0, sizeof(df_timecol));
  516.  
  517.     df_binary = 1;
  518.     /*}}} */
  519.  
  520.     assert(max_using <= NCOL);
  521.  
  522.     /* empty name means re-use last one */
  523.     if (isstring(c_token) && token_len(c_token) == 2) {
  524.     if (!filename || !*filename)
  525.         int_error("No previous filename",c_token);
  526.     } else {
  527.     filename = gp_realloc(filename, token_len(c_token), "datafile name");
  528.     quote_str(filename, c_token, token_len(c_token));
  529.     }
  530.     name_token = c_token++;
  531.  
  532.     /* defer opening until we have parsed the modifiers... */
  533.  
  534.     /*{{{  look for binary / matrix */
  535.     df_binary = df_matrix = FALSE;
  536.  
  537.     if (almost_equals(c_token, "bin$ary")) {
  538.     ++c_token;
  539.     df_binary = TRUE;
  540.     df_matrix = TRUE;
  541.     } else if (almost_equals(c_token, "mat$rix")) {
  542.     ++c_token;
  543.     df_matrix = TRUE;
  544.     }
  545.     /*}}} */
  546.  
  547.     /*{{{  deal with index */
  548.     if (almost_equals(c_token, "i$ndex")) {
  549.     struct value a;
  550.  
  551.     if (df_binary)
  552.         int_error("Binary file format does not allow more than one surface per file", c_token);
  553.  
  554.     ++c_token;
  555.     df_lower_index = (int) real(const_express(&a));
  556.     if (equals(c_token, ":")) {
  557.         ++c_token;
  558.         df_upper_index = (int) magnitude(const_express(&a));
  559.         if (df_upper_index < df_lower_index)
  560.         int_error("Upper index should be bigger than lower index", c_token);
  561.  
  562.         if (equals(c_token, ":")) {
  563.         ++c_token;
  564.         df_index_step = (int) magnitude(const_express(&a));
  565.         if (df_index_step < 1)
  566.             int_error("Index step must be positive", c_token);
  567.         }
  568.     } else
  569.         df_upper_index = df_lower_index;
  570.     }
  571.     /*}}} */
  572.  
  573.     /*{{{  deal with every */
  574.     if (almost_equals(c_token, "ev$ery")) {
  575.     struct value a;
  576.  
  577.     fast_columns = 0;    /* corey@cac */
  578.     /* allow empty fields - every a:b:c::e
  579.      * we have already established the defaults
  580.      */
  581.  
  582.     if (!equals(++c_token, ":")) {
  583.         everypoint = (int) real(const_express(&a));
  584.         if (everypoint < 1)
  585.         int_error("Expected positive integer", c_token);
  586.     }
  587.     /* if it fails on first test, no more tests will succeed. If it
  588.      * fails on second test, next test will succeed with correct c_token
  589.      */
  590.     if (equals(c_token, ":") && !equals(++c_token, ":")) {
  591.         everyline = (int) real(const_express(&a));
  592.         if (everyline < 1)
  593.         int_error("Expected positive integer", c_token);
  594.     }
  595.     if (equals(c_token, ":") && !equals(++c_token, ":")) {
  596.         firstpoint = (int) real(const_express(&a));
  597.         if (firstpoint < 0)
  598.         int_error("Expected non-negative integer", c_token);
  599.     }
  600.     if (equals(c_token, ":") && !equals(++c_token, ":")) {
  601.         firstline = (int) real(const_express(&a));
  602.         if (firstline < 0)
  603.         int_error("Expected non-negative integer", c_token);
  604.     }
  605.     if (equals(c_token, ":") && !equals(++c_token, ":")) {
  606.         lastpoint = (int) real(const_express(&a));
  607.         if (lastpoint < firstpoint)
  608.         int_error("Last point must not be before first point", c_token);
  609.     }
  610.     if (equals(c_token, ":")) {
  611.         ++c_token;
  612.         lastline = (int) real(const_express(&a));
  613.         if (lastline < firstline)
  614.         int_error("Last line must not be before first line", c_token);
  615.     }
  616.     }
  617.     /*}}} */
  618.  
  619.     /*{{{  deal with thru */
  620.     /* jev -- support for passing data from file thru user function */
  621.  
  622.     if (almost_equals(c_token, "thru$")) {
  623.     c_token++;
  624.     if (ydata_func.at)
  625.         free(ydata_func.at);
  626.     strcpy(c_dummy_var[0], dummy_var[0]);
  627.     /* allow y also as a dummy variable.
  628.      * during plot, c_dummy_var[0] and [1] are 'sacred'
  629.      * ie may be set by  splot [u=1:2] [v=1:2], and these
  630.      * names are stored only in c_dummy_var[]
  631.      * so choose dummy var 2 - can anything vital be here ?
  632.      */
  633.     dummy_func = &ydata_func;
  634.     strcpy(c_dummy_var[2], "y");
  635.     ydata_func.at = perm_at();
  636.     dummy_func = NULL;
  637.     } else {
  638.     if (ydata_func.at)
  639.         free(ydata_func.at);
  640.     ydata_func.at = NULL;
  641.     }
  642.     /*}}} */
  643.  
  644.     /*{{{  deal with using */
  645.     if (almost_equals(c_token, "u$sing")) {
  646.     if (!END_OF_COMMAND && !isstring(++c_token)) {
  647.         struct value a;
  648.  
  649.         do {        /* must be at least one */
  650.         if (df_no_use_specs >= max_using)
  651.             int_error("Too many columns in using specification", c_token);
  652.  
  653.         if (equals(c_token, ":")) {
  654.             /* empty specification - use default */
  655.             use_spec[df_no_use_specs].column = df_no_use_specs;
  656.             ++df_no_use_specs;
  657.             /* do not increment c+token ; let while() find the : */
  658.         } else if (equals(c_token, "(")) {
  659.             fast_columns = 0;    /* corey@cac */
  660.             dummy_func = NULL;    /* no dummy variables active */
  661.             use_spec[df_no_use_specs++].at = perm_at();        /* it will match ()'s */
  662.         } else {
  663.             int col = (int) real(const_express(&a));
  664.             if (col < -2)
  665.             int_error("Column must be >= -2", c_token);
  666.             use_spec[df_no_use_specs++].column = col;
  667.         }
  668.         } while (equals(c_token, ":") && ++c_token);
  669.     }
  670.     if (!END_OF_COMMAND && isstring(c_token)) {
  671.         if (df_binary)
  672.         int_error("Format string meaningless with binary data", NO_CARET);
  673.  
  674.         quote_str(df_format, c_token, MAX_LINE_LEN);
  675.         if (!valid_format(df_format))
  676.         int_error("Please use a double conversion %lf", c_token);
  677.  
  678.         c_token++;        /* skip format */
  679.     }
  680.     }
  681.     /*}}} */
  682.  
  683.     /*{{{  more variable inits */
  684.     point_count = -1;        /* we preincrement */
  685.     line_count = 0;
  686.  
  687.     /* here so it's not done for every line in df_readline */
  688.     if (max_line_len < 160)
  689.     line = (char *) gp_alloc(max_line_len = 160, "datafile line buffer");
  690.  
  691.  
  692.     /*}}} */
  693.  
  694.  
  695. /*{{{  open file */
  696. #if defined(PIPES)
  697.     if (*filename == '<') {
  698.     if ((data_fp = popen(filename + 1, "r")) == (FILE *) NULL)
  699.         os_error("cannot create pipe for data", name_token);
  700.     else
  701.         pipe_open = TRUE;
  702.     } else
  703. #endif /* PIPES */
  704.     if (*filename == '-') {
  705.     data_fp = lf_top();
  706.     if (!data_fp)
  707.         data_fp = stdin;
  708.     mixed_data_fp = TRUE;    /* don't close command file */
  709.     } else {
  710.     char msg[MAX_LINE_LEN+1];
  711. #ifdef HAVE_SYS_STAT_H
  712.     struct stat statbuf;
  713.  
  714.     if ((stat(filename, &statbuf) > -1) &&
  715.         !S_ISREG(statbuf.st_mode) && !S_ISFIFO(statbuf.st_mode)) {
  716.         sprintf(msg, "\"%s\" is not a regular file or pipe", filename);
  717.         os_error(msg, name_token);
  718.     }
  719. #endif /* HAVE_SYS_STAT_H */
  720.     if ((data_fp = fopen(filename, df_binary ? "rb" : "r")) == (FILE *) NULL) {
  721.         /* one day we will have proper printf-style error reporting fns */
  722.         sprintf(msg, "can't read data file \"%s\"", filename);
  723.         os_error(msg, name_token);
  724.     }
  725.     }
  726. /*}}} */
  727.  
  728.     return df_no_use_specs;
  729. }
  730. /*}}} */
  731.  
  732. /*{{{  void df_close() */
  733. void df_close()
  734. {
  735.     int i;
  736.     /* paranoid - mark $n and column(n) as invalid */
  737.     df_no_cols = 0;
  738.  
  739.     if (!data_fp)
  740.     return;
  741.  
  742.     if (ydata_func.at) {
  743.     free(ydata_func.at);
  744.     ydata_func.at = NULL;
  745.     }
  746.     /*{{{  free any use expression storage */
  747.     for (i = 0; i < df_no_use_specs; ++i)
  748.     if (use_spec[i].at) {
  749.         free(use_spec[i].at);
  750.         use_spec[i].at = NULL;
  751.     }
  752.     /*}}} */
  753.  
  754.     if (!mixed_data_fp) {
  755. #if defined(PIPES)
  756.     if (pipe_open) {
  757.         (void) pclose(data_fp);
  758.         pipe_open = FALSE;
  759.     } else
  760. #endif /* PIPES */
  761.         (void) fclose(data_fp);
  762.     }
  763.     mixed_data_fp = FALSE;
  764.     data_fp = NULL;
  765. }
  766.  
  767. /*}}} */
  768.  
  769. /*{{{  int df_readline(v, max) */
  770. /* do the hard work... read lines from file,
  771.  * - use blanks to get index number
  772.  * - ignore lines outside range of indices required
  773.  * - fill v[] based on using spec if given
  774.  */
  775.  
  776. int df_readline(v, max)
  777. double v[];
  778. int max;
  779. {
  780.     char *s;
  781.  
  782.     assert(data_fp != NULL);
  783.     assert(!df_binary);
  784.     assert(max_line_len);    /* alloc-ed in df_open() */
  785.     assert(max <= NCOL);
  786.  
  787.     /* catch attempt to read past EOF on mixed-input */
  788.     if (df_eof)
  789.     return DF_EOF;
  790.  
  791.     while ((s = df_gets()) != NULL)
  792.     /*{{{  process line */
  793.     {
  794.     int line_okay = 1;
  795.     int output = 0;        /* how many numbers written to v[] */
  796.  
  797.     ++df_line_number;
  798.     df_no_cols = 0;
  799.  
  800.     /*{{{  check for blank lines, and reject by index/every */
  801.     /*{{{  skip leading spaces */
  802.     while (isspace((int)*s))
  803.         ++s;        /* will skip the \n too, to point at \0  */
  804.     /*}}} */
  805.  
  806.     /*{{{  skip comments */
  807.     if (is_comment(*s))
  808.         continue;        /* ignore comments */
  809.     /*}}} */
  810.  
  811.     /*{{{  check EOF on mixed data */
  812.     if (mixed_data_fp && is_EOF(*s)) {
  813.         df_eof = 1;        /* trap attempts to read past EOF */
  814.         return DF_EOF;
  815.     }
  816.     /*}}} */
  817.  
  818.     /*{{{  its a blank line - update counters and continue or return */
  819.     if (*s == 0) {
  820.         /* argh - this is complicated !  we need to
  821.          *   ignore it if we haven't reached first index
  822.          *   report EOF if passed last index
  823.          *   report blank line unless we've already done 2 blank lines
  824.          *
  825.          * - I have probably missed some obvious way of doing all this,
  826.          * but its getting late
  827.          */
  828.  
  829.         point_count = -1;    /* restart counter within line */
  830.  
  831.         if (++blank_count == 1) {
  832.         /* first blank line */
  833.         ++line_count;
  834.         }
  835.  
  836.         /* just reached end of a group/surface */
  837.         if (blank_count == 2) {
  838.         ++df_current_index;
  839.         line_count = 0;
  840.         df_datum = -1;
  841.         /* ignore line if current_index has just become
  842.          * first required one - client doesn't want this
  843.          * blank line. While we're here, check for <=
  844.          * - we need to do it outside this conditional, but
  845.          * probably no extra cost at assembler level
  846.          */
  847.         if (df_current_index <= df_lower_index)
  848.             continue;    /* dont tell client */
  849.  
  850.         /* df_upper_index is MAXINT-1 if we are not doing index */
  851.         if (df_current_index > df_upper_index) {
  852.             /* oops - need to gobble rest of input if mixed */
  853.             if (mixed_data_fp)
  854.             continue;
  855.             else {
  856.             df_eof = 1;
  857.             return DF_EOF;    /* no point continuing */
  858.             }
  859.         }
  860.         }
  861.         /* dont tell client if we haven't reached first index */
  862.         if (df_current_index < df_lower_index)
  863.         continue;
  864.  
  865.         /* ignore blank lines after blank_index */
  866.         if (blank_count > 2)
  867.         continue;
  868.  
  869.         return DF_FIRST_BLANK - (blank_count - 1);
  870.     }
  871.     /*}}} */
  872.  
  873.     /* get here => was not blank */
  874.  
  875.     blank_count = 0;
  876.  
  877.     /*{{{  ignore points outside range of index */
  878.     /* we try to return end-of-file as soon as we pass upper index,
  879.      * but for mixed input stream, we must skip garbage
  880.      */
  881.  
  882.     if (df_current_index < df_lower_index ||
  883.         df_current_index > df_upper_index ||
  884.         ((df_current_index - df_lower_index) % df_index_step) != 0)
  885.         continue;
  886.     /*}}} */
  887.  
  888.     /*{{{  reject points by every */
  889.     /* accept only lines with (line_count%everyline) == 0 */
  890.  
  891.     if (line_count < firstline || line_count > lastline ||
  892.         (line_count - firstline) % everyline != 0
  893.         )
  894.         continue;
  895.  
  896.     /* update point_count. ignore point if point_count%everypoint != 0 */
  897.  
  898.     if (++point_count < firstpoint || point_count > lastpoint ||
  899.         (point_count - firstpoint) % everypoint != 0
  900.         )
  901.         continue;
  902.     /*}}} */
  903.     /*}}} */
  904.  
  905.     ++df_datum;
  906.  
  907.     /*{{{  do a sscanf */
  908.     if (*df_format)    {
  909.         int i;
  910.  
  911.         assert(NCOL == 7);
  912.  
  913.         /* check we have room for at least 7 columns */
  914.         if (df_max_cols < 7)
  915.         df_column = (df_column_struct *) gp_realloc(df_column, (df_max_cols = 7) * sizeof(df_column_struct), "datafile columns");
  916.  
  917.         df_no_cols = sscanf(line, df_format,
  918.                 &df_column[0].datum,
  919.                 &df_column[1].datum,
  920.                 &df_column[2].datum,
  921.                 &df_column[3].datum,
  922.                 &df_column[4].datum,
  923.                 &df_column[5].datum,
  924.                 &df_column[6].datum);
  925.  
  926.         if (df_no_cols == EOF) {
  927.         df_eof = 1;
  928.         return DF_EOF;    /* tell client */
  929.         }
  930.         for (i = 0; i < df_no_cols; ++i) {    /* may be zero */
  931.         df_column[i].good = DF_GOOD;
  932.         df_column[i].position = NULL;    /* cant get a time */
  933.         }
  934.     }
  935.     /*}}} */
  936.     else
  937.         df_tokenise(s);
  938.  
  939.     /*{{{  copy column[] to v[] via use[] */
  940.     {
  941.         int limit = (df_no_use_specs ? df_no_use_specs : NCOL);
  942.         if (limit > max)
  943.         limit = max;
  944.  
  945.         for (output = 0; output < limit; ++output) {
  946.         /* if there was no using spec, column is output+1 and at=NULL */
  947.         int column = use_spec[output].column;
  948.  
  949.         if (use_spec[output].at) {
  950.             struct value a;
  951.             /* no dummy values to set up prior to... */
  952.             evaluate_at(use_spec[output].at, &a);
  953.             if (undefined)
  954.             return DF_UNDEFINED;    /* store undefined point in plot */
  955.  
  956.             v[output] = real(&a);
  957.         } else if (column == -2) {
  958.             v[output] = df_current_index;
  959.         } else if (column == -1) {
  960.             v[output] = line_count;
  961.         } else if (column == 0) {
  962.             v[output] = df_datum;    /* using 0 */
  963.         } else if (column <= 0)        /* really < -2, but */
  964.             int_error("internal error: column <= 0 in datafile.c", NO_CARET);
  965.         else if (df_timecol[output]) {
  966.             struct tm tm;
  967.             if (column > df_no_cols ||
  968.             df_column[column - 1].good == DF_MISSING ||
  969.             !df_column[column - 1].position ||
  970.             !gstrptime(df_column[column - 1].position, timefmt, &tm)
  971.             ) {
  972.             /* line bad only if user explicitly asked for this column */
  973.             if (df_no_use_specs)
  974.                 line_okay = 0;
  975.  
  976.             /* return or ignore line depending on line_okay */
  977.             break;
  978.             }
  979.             v[output] = (double) gtimegm(&tm);
  980.         } else {    /* column > 0 */
  981.             if ((column <= df_no_cols) && df_column[column - 1].good == DF_GOOD)
  982.             v[output] = df_column[column - 1].datum;
  983.             else {
  984.             /* line bad only if user explicitly asked for this column */
  985.             if (df_no_use_specs)
  986.                 line_okay = 0;
  987.             break;    /* return or ignore depending on line_okay */
  988.             }
  989.         }
  990.         }
  991.     }
  992.     /*}}} */
  993.  
  994.     if (!line_okay)
  995.         continue;
  996.  
  997.     /* output == df_no_use_specs if using was specified
  998.      * - actually, smaller of df_no_use_specs and max
  999.      */
  1000.     assert(df_no_use_specs == 0 || output == df_no_use_specs || output == max);
  1001.  
  1002.     return output;
  1003.  
  1004.     }
  1005.     /*}}} */
  1006.  
  1007.     /* get here => fgets failed */
  1008.  
  1009.     /* no longer needed - mark column(x) as invalid */
  1010.     df_no_cols = 0;
  1011.  
  1012.     df_eof = 1;
  1013.     return DF_EOF;
  1014. }
  1015. /*}}} */
  1016.  
  1017. /*{{{  int df_2dbinary(this_plot) */
  1018. int df_2dbinary(this_plot)
  1019. struct curve_points *this_plot;
  1020. {
  1021.     int_error("Binary file format for 2d data not yet defined", NO_CARET);
  1022.     return 0;            /* keep compiler happy */
  1023. }
  1024. /*}}} */
  1025.  
  1026. /*{{{  int df_3dmatrix(this_plot, ret_this_iso) */
  1027. /*
  1028.  * formerly in gnubin.c
  1029.  *
  1030.  * modified by div for 3.6
  1031.  *   obey the 'every' field from df_open
  1032.  *   outrange points are marked as such, not omitted
  1033.  *   obey using - treat x as column 1, y as col 2 and z as col 3
  1034.  *   ( ie $1 gets x, $2 gets y, $3 gets z)
  1035.  *
  1036.  *  we are less optimal for case of log plot and no using spec,
  1037.  * (call log too often) but that is price for flexibility
  1038.  * I suspect it didn't do autoscaling of x and y for log scale
  1039.  * properly ?
  1040.  *
  1041.  * Trouble figuring out file format ! Is it
  1042.  
  1043.  width  x1  x2  x3  x4  x5 ...
  1044.  y1   z11 z12 z13 z14 z15 ...
  1045.  y2   x21 z22 z23 .....
  1046.  .    .
  1047.  .        .
  1048.  .             .
  1049.  
  1050.  * with perhaps x and y swapped...
  1051.  *
  1052.  * - presumably rows continue to end of file, hence no indexing...
  1053.  *
  1054.  * Last update: 3/3/92 for Gnuplot 3.24.
  1055.  * Created from code for written by RKC for gnuplot 2.0b.
  1056.  *
  1057.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  1058.  * Added user-specified bases for log scaling.
  1059.  *
  1060.  * Copyright (c) 1991,1992 Robert K. Cunningham, MIT Lincoln Laboratory
  1061.  *
  1062.  */
  1063.  
  1064. /*
  1065.    Here we keep putting new plots onto the end of the linked list
  1066.  
  1067.    We assume the data's x,y values have x1<x2, x2<x3... and 
  1068.    y1<y2, y2<y3... .
  1069.    Actually, I think the assumption is less strong than that--it looks like
  1070.    the direction just has to be the same.
  1071.    This routine expects the following to be properly initialized:
  1072.    is_log_x, is_log_y, and is_log_z 
  1073.    base_log_x, base_log_y, and base_log_z 
  1074.    log_base_log_x, log_base_log_y, and log_base_log_z 
  1075.    xmin,ymin, and zmin
  1076.    xmax,ymax, and zmax
  1077.    autoscale_lx, autoscale_ly, and autoscale_lz
  1078.  
  1079.    does the autoscaling into the array versions (min_array[], max_array[])
  1080.  */
  1081.  
  1082. int df_3dmatrix(this_plot)
  1083. struct surface_points *this_plot;
  1084. {
  1085.     float GPFAR *GPFAR * dmatrix, GPFAR * rt, GPFAR * ct;
  1086.     int nr, nc;
  1087.     int width, height;
  1088.     int row, col;
  1089.     struct iso_curve *this_iso;
  1090.     double used[3];        /* output from using manip */
  1091.     struct coordinate GPHUGE *point;    /* HBB 980308: added 'GPHUGE' flag */
  1092.  
  1093.     assert(df_matrix);
  1094.  
  1095.     if (df_eof)
  1096.     return 0;        /* hope caller understands this */
  1097.  
  1098.     if (df_binary) {
  1099.     if (!fread_matrix(data_fp, &dmatrix, &nr, &nc, &rt, &ct))
  1100.         int_error("Binary file read error: format unknown!", NO_CARET);
  1101.     /* fread_matrix() drains the file */
  1102.     df_eof = 1;
  1103.     } else {
  1104.     if (!(dmatrix = df_read_matrix(&nr, &nc))) {
  1105.         df_eof = 1;
  1106.         return 0;
  1107.     }
  1108.     rt = NULL;
  1109.     ct = NULL;
  1110.     }
  1111.  
  1112.     if (nc == 0 || nr == 0)
  1113.     int_error("Read grid of zero height or zero width", NO_CARET);
  1114.  
  1115.     this_plot->plot_type = DATA3D;
  1116.     this_plot->has_grid_topology = TRUE;
  1117.  
  1118.     if (df_no_use_specs != 0 && df_no_use_specs != 3)
  1119.     int_error("Current implementation requires full using spec", NO_CARET);
  1120.  
  1121.     if (df_max_cols < 3 &&
  1122.     !(df_column = (df_column_struct *) gp_realloc(df_column, (df_max_cols = 3) * sizeof(df_column_struct), "datafile columns"))
  1123.     )
  1124.     int_error("Out of store in binary read", c_token);
  1125.  
  1126.     df_no_cols = 3;
  1127.     df_column[0].good = df_column[1].good = df_column[2].good = DF_GOOD;
  1128.  
  1129.     assert(everyline > 0);
  1130.     assert(everypoint > 0);
  1131.     width = (nc - firstpoint + everypoint - 1) / everypoint;    /* ? ? ? ? ? */
  1132.     height = (nr - firstline + everyline - 1) / everyline;    /* ? ? ? ? ? */
  1133.  
  1134.     for (row = firstline; row < nr; row += everyline) {
  1135.     df_column[1].datum = rt ? rt[row] : row;
  1136.  
  1137.     /*Allocate the correct number of entries */
  1138.     this_iso = iso_alloc(width);
  1139.  
  1140.     point = this_iso->points;
  1141.  
  1142.     /* Cycle through data */
  1143.     for (col = firstpoint; col < nc; col += everypoint, ++point) {
  1144.         /*{{{  process one point */
  1145.         int i;
  1146.  
  1147.         df_column[0].datum = ct ? ct[col] : col;
  1148.         df_column[2].datum = dmatrix[row][col];
  1149.  
  1150.         /*{{{  pass through using spec */
  1151.         for (i = 0; i < 3; ++i) {
  1152.         int column = use_spec[i].column;
  1153.  
  1154.         if (df_no_use_specs == 0)
  1155.             used[i] = df_column[i].datum;
  1156.         else if (use_spec[i].at) {
  1157.             struct value a;
  1158.             evaluate_at(use_spec[i].at, &a);
  1159.             if (undefined) {
  1160.             point->type = UNDEFINED;
  1161.             goto skip;    /* continue _outer_ loop */
  1162.             }
  1163.             used[i] = real(&a);
  1164.         } else if (column < 1 || column > df_no_cols) {
  1165.             point->type = UNDEFINED;
  1166.             goto skip;
  1167.         } else
  1168.             used[i] = df_column[column - 1].datum;
  1169.         }
  1170.         /*}}} */
  1171.  
  1172.         point->type = INRANGE;    /* so far */
  1173.  
  1174.         /*{{{  autoscaling/clipping */
  1175.         /*{{{  autoscale/range-check x */
  1176.         if (used[0] > 0 || !is_log_x) {
  1177.         if (used[0] < min_array[FIRST_X_AXIS]) {
  1178.             if (autoscale_lx & 1)
  1179.             min_array[FIRST_X_AXIS] = used[0];
  1180.             else
  1181.             point->type = OUTRANGE;
  1182.         }
  1183.         if (used[0] > max_array[FIRST_X_AXIS]) {
  1184.             if (autoscale_lx & 2)
  1185.             max_array[FIRST_X_AXIS] = used[0];
  1186.             else
  1187.             point->type = OUTRANGE;
  1188.         }
  1189.         }
  1190.         /*}}} */
  1191.  
  1192.         /*{{{  autoscale/range-check y */
  1193.         if (used[1] > 0 || !is_log_y) {
  1194.         if (used[1] < min_array[FIRST_Y_AXIS]) {
  1195.             if (autoscale_ly & 1)
  1196.             min_array[FIRST_Y_AXIS] = used[1];
  1197.             else
  1198.             point->type = OUTRANGE;
  1199.         }
  1200.         if (used[1] > max_array[FIRST_Y_AXIS]) {
  1201.             if (autoscale_ly & 2)
  1202.             max_array[FIRST_Y_AXIS] = used[1];
  1203.             else
  1204.             point->type = OUTRANGE;
  1205.         }
  1206.         }
  1207.         /*}}} */
  1208.  
  1209.         /*{{{  autoscale/range-check z */
  1210.         if (used[2] > 0 || !is_log_z) {
  1211.         if (used[2] < min_array[FIRST_Z_AXIS]) {
  1212.             if (autoscale_lz & 1)
  1213.             min_array[FIRST_Z_AXIS] = used[2];
  1214.             else
  1215.             point->type = OUTRANGE;
  1216.         }
  1217.         if (used[2] > max_array[FIRST_Z_AXIS]) {
  1218.             if (autoscale_lz & 2)
  1219.             max_array[FIRST_Z_AXIS] = used[2];
  1220.             else
  1221.             point->type = OUTRANGE;
  1222.         }
  1223.         }
  1224.         /*}}} */
  1225.         /*}}} */
  1226.  
  1227.         /*{{{  log x */
  1228.         if (is_log_x) {
  1229.         if (used[0] < 0.0) {
  1230.             point->type = UNDEFINED;
  1231.             goto skip;
  1232.         } else if (used[0] == 0.0) {
  1233.             point->type = OUTRANGE;
  1234.             used[0] = -VERYLARGE;
  1235.         } else
  1236.             used[0] = log(used[0]) / log_base_log_x;
  1237.         }
  1238.         /*}}} */
  1239.  
  1240.         /*{{{  log y */
  1241.         if (is_log_y) {
  1242.         if (used[1] < 0.0) {
  1243.             point->type = UNDEFINED;
  1244.             goto skip;
  1245.         } else if (used[1] == 0.0) {
  1246.             point->type = OUTRANGE;
  1247.             used[1] = -VERYLARGE;
  1248.         } else
  1249.             used[1] = log(used[1]) / log_base_log_y;
  1250.         }
  1251.         /*}}} */
  1252.  
  1253.         /*{{{  log z */
  1254.         if (is_log_z) {
  1255.         if (used[2] < 0.0) {
  1256.             point->type = UNDEFINED;
  1257.             goto skip;
  1258.         } else if (used[2] == 0.0) {
  1259.             point->type = OUTRANGE;
  1260.             used[2] = -VERYLARGE;
  1261.         } else
  1262.             used[2] = log(used[2]) / log_base_log_z;
  1263.         }
  1264.         /*}}} */
  1265.  
  1266.         point->x = used[0];
  1267.         point->y = used[1];
  1268.         point->z = used[2];
  1269.  
  1270.  
  1271.         /* some of you wont like this, but I say goto is for this */
  1272.  
  1273.       skip:
  1274.         ;            /* ansi requires this */
  1275.         /*}}} */
  1276.     }
  1277.     this_iso->p_count = width;
  1278.     this_iso->next = this_plot->iso_crvs;
  1279.     this_plot->iso_crvs = this_iso;
  1280.     this_plot->num_iso_read++;
  1281.     }
  1282.  
  1283.     free_matrix(dmatrix, 0, nr - 1, 0, nc - 1);
  1284.     if (rt)
  1285.     free_vector(rt, 0, nr - 1);
  1286.     if (ct)
  1287.     free_vector(ct, 0, nc - 1);
  1288.     return (nc);
  1289. }
  1290. /*}}} */
  1291.  
  1292. /* stuff for implementing the call-backs for picking up data values
  1293.  * do it here so we can make the variables private to this file
  1294.  */
  1295.  
  1296. /*{{{  void f_dollars(x) */
  1297. void f_dollars(x)
  1298. union argument *x;
  1299. {
  1300.     int column = x->v_arg.v.int_val - 1;
  1301.     /* we checked it was an integer >= 0 at compile time */
  1302.     struct value a;
  1303.  
  1304.     if (column == -1) {
  1305.     push(Gcomplex(&a, (double) df_datum, 0.0));    /* $0 */
  1306.     } else if (column >= df_no_cols || df_column[column].good != DF_GOOD) {
  1307.     undefined = TRUE;
  1308.     push(&(x->v_arg));    /* this okay ? */
  1309.     } else
  1310.     push(Gcomplex(&a, df_column[column].datum, 0.0));
  1311. }
  1312. /*}}} */
  1313.  
  1314. /*{{{  void f_column() */
  1315. void f_column()
  1316. {
  1317.     struct value a;
  1318.     int column;
  1319.     (void) pop(&a);
  1320.     column = (int) real(&a) - 1;
  1321.     if (column == -2)
  1322.     push(Ginteger(&a, line_count));
  1323.     else if (column == -1)    /* $0 = df_datum */
  1324.     push(Gcomplex(&a, (double) df_datum, 0.0));
  1325.     else if (column < 0 || column >= df_no_cols || df_column[column].good != DF_GOOD) {
  1326.     undefined = TRUE;
  1327.     push(&a);        /* any objection to this ? */
  1328.     } else
  1329.     push(Gcomplex(&a, df_column[column].datum, 0.0));
  1330. }
  1331. /*}}} */
  1332.  
  1333. /*{{{  void f_valid() */
  1334. void f_valid()
  1335. {
  1336.     struct value a;
  1337.     int column, good;
  1338.     (void) pop(&a);
  1339.     column = (int) magnitude(&a) - 1;
  1340.     good = column >= 0 && column < df_no_cols && df_column[column].good == DF_GOOD;
  1341.     push(Ginteger(&a, good));
  1342. }
  1343.  
  1344. /*}}} */
  1345.  
  1346. /*{{{  void f_timecolumn() */
  1347. void f_timecolumn()
  1348. {
  1349.     struct value a;
  1350.     int column;
  1351.     struct tm tm;
  1352.     (void) pop(&a);
  1353.     column = (int) magnitude(&a) - 1;
  1354.     if (column < 0 || column >= df_no_cols ||
  1355.     !df_column[column].position ||
  1356.     !gstrptime(df_column[column].position, timefmt, &tm)
  1357.     ) {
  1358.     undefined = TRUE;
  1359.     push(&a);        /* any objection to this ? */
  1360.     } else
  1361.     push(Gcomplex(&a, gtimegm(&tm), 0.0));
  1362. }
  1363. /*}}} */
  1364.  
  1365. #if 0                /* not used */
  1366. /* count columns in timefmt */
  1367. /*{{{  static int get_time_cols(fmt) */
  1368. static int get_time_cols(fmt)
  1369. char *fmt;            /* format string */
  1370. {
  1371.     int cnt, i;
  1372.     char *p;
  1373.  
  1374.     p = fmt;
  1375.     cnt = 0;
  1376.     while (isspace(*p))
  1377.     p++;
  1378.     if (!strlen(p))
  1379.     int_error("Empty time-data format", NO_CARET);
  1380.     cnt++;
  1381.     for (i = 0; i < strlen(p) - 1; i++) {
  1382.     if (isspace(p[i]) && !isspace(p[i + 1]))
  1383.         cnt++;
  1384.     }
  1385.     return (cnt);
  1386. }
  1387. /*}}} */
  1388.  
  1389. /* modify default use_spec, applies for no user spec and time datacolumns */
  1390. /*{{{  static void mod_def_usespec(specno,jump) */
  1391. static void mod_def_usespec(specno, jump)
  1392. int specno;            /* which spec in ?:?:? */
  1393. int jump;            /* no of columns in timefmt (time data) */
  1394. {
  1395.     int i;
  1396.  
  1397.     for (i = specno + 1; i < NCOL; ++i)
  1398.     use_spec[i].column += jump;    /* add no of columns in time to the rest */
  1399.     df_no_use_specs = 0;
  1400. }
  1401. /*}}} */
  1402. #endif /* not used */
  1403.  
  1404. /*{{{  static int check_missing(s) */
  1405. static int check_missing(s)
  1406. char *s;
  1407. {
  1408.     if (missing_val != NULL) {
  1409.     int len = strlen(missing_val);
  1410.     if (strncmp(s, missing_val, len) == 0 &&
  1411.         (isspace((int)s[len]) || !s[len])) {
  1412.         return (1);;    /* store undefined point in plot */
  1413.     }
  1414.     }
  1415.     return (0);
  1416. }
  1417. /*}}} */
  1418.